package com.hd123.rumba.gwt.widget2.client.grid;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.hd123.gwt.types.JsBigDecimal;
import com.hd123.rumba.gwt.widget2.client.form.HasNumberFormat;
import com.hd123.rumba.gwt.widget2.client.form.RSimpleCheckBox;
import com.hd123.rumba.gwt.widget2.client.grid.renderer.RCellRenderer;
import com.hd123.rumba.gwt.widget2.client.grid.renderer.RCheckBoxRenderer;
import com.hd123.rumba.gwt.widget2.client.grid.renderer.RCheckBoxRendererFactory;

/**
 * 表格<br>
 * 性能要点：尽量在调用rebuild之后再把grid加入到所属的容器组件中，这比先加入容器再rebuild要快一些。
 * 
 * @author LiQi
 * 
 */
public class RGrid extends Grid {

  /** 样式 */
  private static final String STYLENAME = "rb-Grid";
  private static final String STYLENAME_HEADER = "rb-Grid-header";
  private static final String STYLENAME_HEADER_HOVER = "rb-Grid-header-hover";
  private static final String STYLENAME_HEADER_SORT = "rb-Grid-header-sort";
  private static final String STYLENAME_SORTICON = "rb-Grid-sorticon";
  private static final String STYLENAME_HEADERWIDGET = "rb-Grid-headerwidget";
  private static final String STYLENAME_CAPTION = "rb-Grid-caption";
  private static final String STYLENAME_ROW = "rb-Grid-row";
  private static final String STYLENAME_ROW_STRIP = "rb-Grid-row-strip";
  private static final String STYLENAME_ROW_HOVER = "rb-Grid-row-hover";
  private static final String STYLENAME_ROW_SELECTED = "rb-Grid-row-selected";
  private static final String STYLENAME_FOOTER = "rb-Grid-footer";

  private static final String DEPENDENT_STYLENAME_ASC = "asc";
  private static final String DEPENDENT_STYLENAME_DESC = "desc";

  /** 排序方式：顺序 */
  public static final String SORT_ASC = "asc";

  /** 排序方式：逆序 */
  public static final String SORT_DESC = "desc";

  /** 列定义 */
  protected List<RGridColumnDef> columnDefs;

  /** 带缓存的数据提供者 */
  protected DataProviderCache providerCache;

  /** 自定义合计数据提供者 */
  protected RGridSummaryProvider customSummaryProvider;

  /**
   * 默认的合计数据提供者，
   * 被summaryMethod不等于SUMMARY_METHOD_CUSTOM和SUMMARY_METHOD_NONE的列使用
   */
  protected RGridSummaryProvider defaultSummaryProvider;

  /** RGridClickListener集合 */
  protected RGridClickListenerCollection clickListeners;

  /** RGridDrawListener集合 */
  protected RGridDrawListenerCollection drawListeners;

  /** RGridSortListener集合 */
  protected RGridSortListenerCollection sortListeners;

  /** 表头占用的行数 */
  protected int headerRowCount = 1;

  /** 是否显示表头 */
  protected boolean showHeader = true;

  /** 表尾占用的行数 */
  protected int footerRowCount = 0;

  /** 是否已经构造过 */
  private boolean build = false;

  /** 当前排序列 */
  private RGridColumnDef sortColDef;

  /** 是否条纹背景 */
  private boolean stripRows = true;

  /** 是否高亮显示鼠标所在行 */
  private boolean hoverRow = false;

  /** 行选择列定义 */
  private RGridColumnDef rowSelectorCol;

  /** 是否显示行选择 */
  private boolean showRowSelector = false;

  /** 是否只能单选 */
  private boolean singleSelection = false;

  /** 行选择事件处理 */
  private RGridClickListener rowSelectorListener;

  /** 所选择行列表 */
  private List<Integer> selections;

  /** 是否有合计栏 */
  private boolean hasSummary = false;

  public RGrid() {
    super();

    columnDefs = new ArrayList();
    selections = new ArrayList();

    setWidth("100%");
    setCellSpacing(1);
    setCellPadding(4);
    setStyleName(STYLENAME);

    sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);

    addClickHandler(new GridClickHandlerAdapter());
  }

  /**
   * 添加列定义，调用rebuild()后生效
   * 
   * @param colDef
   */
  public void addColumnDef(RGridColumnDef colDef) {
    addColumnDef(columnDefs.size(), colDef);
  }

  /**
   * 添加列定义，调用rebuild()后生效
   * 
   * @param index
   *          插入的位置
   * @param colDef
   */
  public void addColumnDef(int index, RGridColumnDef colDef) {
    columnDefs.add(index, colDef);
    colDef.setOwner(this);
    colDef.setIndex(columnDefs.size() - 1);
    if (index == columnDefs.size() - 1)
      colDef.setVisibleIndex(colDef.isVisible() ? getVisibleColumnCount() - 1 : -1);
    else
      recalculateColumnVisibleIndex();

    recalculateHasSummary();
  }

  /**
   * 列定义
   * 
   * @param index
   *          列定义的序号
   * @return
   */
  public RGridColumnDef getColumnDef(int index) {
    return (RGridColumnDef) columnDefs.get(index);

  }

  /**
   * 根据可见列序号查找列定义
   * 
   * @param visibleIndex
   *          可见列序号
   * @return
   */
  public RGridColumnDef getColumnDefByVisibleIndex(int visibleIndex) {
    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (colDef.getVisibleIndex() == visibleIndex)
        return colDef;
    }
    return null;
  }

  /**
   * 可见列数
   * 
   * @return
   */
  public int getVisibleColumnCount() {
    int count = 0;
    for (int col = 0; col < columnDefs.size(); col++)
      if (getColumnDef(col).isVisible())
        count++;
    return count;
  }

  /**
   * 数据提供者
   * 
   * @return
   */
  public RGridDataProvider getProvider() {
    return providerCache;
  }

  /**
   * 设置数据提供者，调用rebuild()或refresh()后生效
   * 
   * @param provider
   */
  public void setProvider(RGridDataProvider provider) {
    if (this.providerCache == null)
      this.providerCache = new DataProviderCache();
    this.providerCache.setProvider(provider);
  }

  /**
   * 自定义合计数据提供者，被summaryMethod为SUMMARY_METHOD_CUSTOM的列使用。
   * 
   * @return
   */
  public RGridSummaryProvider getCustomSummaryProvider() {
    return customSummaryProvider;
  }

  /**
   * 设置自定义合计数据提供者，被summaryMethod为SUMMARY_METHOD_CUSTOM的列使用。
   * 调用rebuild()或refresh()后生效。
   * 
   * @param customSummaryProvider
   */
  public void setCustomSummaryProvider(RGridSummaryProvider customSummaryProvider) {
    this.customSummaryProvider = customSummaryProvider;
  }

  /**
   * 添加RGridClickListener事件监听器
   * 
   * @param listener
   */
  public void addRGridClickListener(RGridClickListener listener) {
    if (clickListeners == null)
      clickListeners = new RGridClickListenerCollection();
    clickListeners.add(listener);
  }

  /**
   * 删除RGridClickListener事件监听器
   * 
   * @param listener
   */
  public void removeRGridClickListener(RGridClickListener listener) {
    if (clickListeners != null)
      clickListeners.remove(listener);
  }

  /**
   * 触发click事件。本方法主要是提供给RCellRendererFactory的实现类使用，RGrid的最终用户请慎用。
   * 
   * @param colDef
   * @param row
   * @param col
   * @param sender
   * @see {@link RGridClickListener#onClick(RGrid, RGridColumnDef, int, int, Widget)}
   */
  public void fireRGridClick(RGridColumnDef colDef, int row, int col, Widget sender) {
    if (clickListeners != null)
      clickListeners.fireClick(this, colDef, row, col, sender);
  }

  /**
   * 添加RGridDrawListener事件监听器
   * 
   * @param listener
   */
  public void addRGridDrawListener(RGridDrawListener listener) {
    if (drawListeners == null)
      drawListeners = new RGridDrawListenerCollection();
    drawListeners.add(listener);
  }

  /**
   * 删除RGridDrawListener事件监听器
   * 
   * @param listener
   */
  public void removeRGridDrawListener(RGridDrawListener listener) {
    if (drawListeners != null)
      drawListeners.remove(listener);
  }

  /**
   * 添加RGridSortListener事件监听器
   * 
   * @param listener
   */
  public void addRGridSortListener(RGridSortListener listener) {
    if (sortListeners == null)
      sortListeners = new RGridSortListenerCollection();
    sortListeners.add(listener);
  }

  /**
   * 删除RGridSortListener事件监听器
   * 
   * @param listener
   */
  public void removeRGridSortListener(RGridSortListener listener) {
    if (sortListeners != null)
      sortListeners.remove(listener);
  }

  /**
   * 表头占用的行数
   * 
   * @return
   */
  public int getHeaderRowCount() {
    return headerRowCount;
  }

  /**
   * 是否显示表头，默认为true
   * 
   * @return
   */
  public boolean isShowHeader() {
    return showHeader;
  }

  /**
   * 设置是否显示表头，默认为true。如果调用本方法时表格已经构造过，则会自动rebuild以便立即生效，
   * 调用者无须再rebuild。
   * 
   * @param showHeader
   */
  public void setShowHeader(boolean showHeader) {
    if (this.showHeader == showHeader)
      return;

    this.showHeader = showHeader;
    headerRowCount = showHeader ? 1 : 0;
    if (build)
      rebuild();
  }

  /**
   * 表尾占用的行数
   * 
   * @return
   */
  public int getFooterRowCount() {
    return footerRowCount;
  }

  /**
   * 重新计算hasSummary和footerRowCount
   * 
   */
  protected void recalculateHasSummary() {
    hasSummary = false;
    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = (RGridColumnDef) columnDefs.get(i);
      if (colDef.getSummaryMethod() != RGridColumnDef.SUMMARY_METHOD_NONE) {
        hasSummary = true;
        break;
      }
    }
    footerRowCount = hasSummary ? 1 : 0;
  }

  /**
   * 根据传入的表格行号计算该行对应的数据行号，即provider行号
   * 
   * @param row
   *          表格行号
   * @return 数据行号
   * @throws IndexOutOfBoundsException
   */
  public int toDataRow(int row) {
    if (row < headerRowCount || row >= getRowCount() - footerRowCount)
      throw new IndexOutOfBoundsException("行号越界");
    return row - headerRowCount;
  }

  /**
   * 是否已经构造过
   * 
   * @return
   */
  public boolean isBuild() {
    return build;
  }

  /**
   * 设置所有列的sortable属性，只对已经添加的列有效。对行选择列无效，行选择列的sortable永远为false。
   * 参见 {@link #buildRowSelectorColumn()}。
   * 
   * @param sortable
   */
  public void setAllColumnsSortable(boolean sortable) {
    for (int i = 0; i < columnDefs.size(); i++)
      getColumnDef(i).setSortable(sortable);
  }

  /**
   * 当前排序列，为null表示没有排序
   * 
   * @return
   */
  public RGridColumnDef getSortColumnDef() {
    return sortColDef;
  }

  /**
   * 是否条纹背景，默认为true
   * 
   * @return
   */
  public boolean isStripRows() {
    return stripRows;
  }

  /**
   * 设置是否条纹背景
   * 
   * @param stripRows
   */
  public void setStripRows(boolean stripRows) {
    if (this.stripRows == stripRows)
      return;

    this.stripRows = stripRows;

    // 刷新条纹背景
    for (int row = headerRowCount; row < getRowCount() - footerRowCount; row++) {
      if (row % 2 == 0) {
        if (stripRows)
          getRowFormatter().addStyleName(row, STYLENAME_ROW_STRIP);
        else
          getRowFormatter().removeStyleName(row, STYLENAME_ROW_STRIP);
      }
    }
  }

  /**
   * 是否高亮显示鼠标所在行，默认为false
   * 
   * @return
   */
  public boolean isHoverRow() {
    return hoverRow;
  }

  /**
   * 设置是否高亮显示鼠标所在行
   * 
   * @param hoverRow
   */
  public void setHoverRow(boolean hoverRow) {
    this.hoverRow = hoverRow;
  }

  /**
   * 清除当前行高亮效果，主要用于弹出对话框中的表格，避免对话框关闭后再次打开看到遗留的上次的当前行高亮效果。
   * 
   */
  public void clearHoverRowStyle() {
    for (int i = headerRowCount; i < getRowCount() - footerRowCount; i++)
      getRowFormatter().removeStyleName(i, STYLENAME_ROW_HOVER);
  }

  /**
   * 是否显示行选择
   * 
   * @return
   */
  public boolean isShowRowSelector() {
    return showRowSelector;
  }

  /**
   * 设置是否显示行选择，rebuild后生效
   * 
   * @param showRowSelector
   */
  public void setShowRowSelector(boolean showRowSelector) {
    this.showRowSelector = showRowSelector;
  }

  /**
   * 是否只能单选，默认为false
   * 
   * @return
   */
  public boolean isSingleSelection() {
    return singleSelection;
  }

  /**
   * 设置是否只能单选，rebuild后生效
   * 
   * @param singleSelection
   */
  public void setSingleSelection(boolean singleSelection) {
    this.singleSelection = singleSelection;
  }

  /**
   * 选择一行
   * <p>
   * 在showRowSelector=false时不起作用，在rebuild之前也不起作用
   * 
   * @param row
   *          行序号
   */
  public void selectRow(int row) {
    if (!showRowSelector || !build)
      return;

    // 选中复选框
    Widget widget = getWidget(row, rowSelectorCol.getVisibleIndex());
    ((RSimpleCheckBox) widget).setChecked(true);

    // 样式
    getRowFormatter().addStyleName(row, STYLENAME_ROW_SELECTED);

    // 单选时清除其它选择的行
    if (singleSelection) {
      for (int i = selections.size() - 1; i >= 0; i--) {
        int selection = ((Integer) selections.get(i)).intValue();
        if (selection == row)
          continue;

        Widget w = getWidget(selection, rowSelectorCol.getVisibleIndex());
        ((RSimpleCheckBox) w).setChecked(false);

        getRowFormatter().removeStyleName(selection, STYLENAME_ROW_SELECTED);
        selections.remove(i);
      }
    }

    // 插入到selections，按照从小到大排序的位置
    Integer selection = new Integer(row);
    if (!selections.contains(selection)) {
      boolean inserted = false;
      for (int i = 0; i < selections.size(); i++) {
        if (selection.compareTo((Integer) selections.get(i)) < 0) {
          selections.add(i, selection);
          inserted = true;
          break;
        }
      }
      if (!inserted)
        selections.add(selection);
    }
  }

  /**
   * 清除选择一行
   * <p>
   * 在showRowSelector=false时不起作用，在rebuild之前也不起作用
   * 
   * @param row
   *          行序号
   */
  public void deselectRow(int row) {
    if (!showRowSelector || !build)
      return;

    Widget widget = getWidget(row, rowSelectorCol.getVisibleIndex());
    ((RSimpleCheckBox) widget).setChecked(false);

    getRowFormatter().removeStyleName(row, STYLENAME_ROW_SELECTED);
    selections.remove(new Integer(row));
  }

  /**
   * 选择所有行
   * <p>
   * 在showRowSelector=false时不起作用，在rebuild之前也不起作用
   * 
   */
  public void selectAllRows() {
    if (!showRowSelector || !build)
      return;

    selections.clear();
    ((RSimpleCheckBox) rowSelectorCol.getHeaderWidget()).setChecked(true);
    for (int row = headerRowCount; row < getRowCount() - footerRowCount; row++) {
      selectRow(row);
    }
  }

  /**
   * 清除所有行的选择
   * <p>
   * 在showRowSelector=false时不起作用，在rebuild之前也不起作用
   * 
   */
  public void deselectAllRows() {
    if (!showRowSelector || !build)
      return;

    selections.clear();
    ((RSimpleCheckBox) rowSelectorCol.getHeaderWidget()).setChecked(false);
    for (int row = headerRowCount; row < getRowCount() - footerRowCount; row++) {
      deselectRow(row);
    }
  }

  /**
   * 所选择行的行号列表，行号是表格的行号，从{@link #getHeaderRowCount()}开始计数。如果
   * {@link #isSingleSelection()}
   * 为true，则列表只有一条记录。rebuild后selections会被清除。
   * 
   * @return
   */
  public List getSelections() {
    return selections;
  }

  /**
   * 判断一行是否被选中
   * 
   * @param row
   *          行号，从0计数
   * @return
   */
  public boolean isRowSelected(int row) {
    if (!showRowSelector)
      return false;
    else
      return selections.contains(new Integer(row));
  }

  /**
   * 是否有合计栏，默认为false。
   * 
   * @return
   */
  public boolean isHasSummary() {
    return hasSummary;
  }

  /**
   * 设置行样式
   * 
   * @param row
   *          行序号，包含表格的表头和表尾
   * @param attr
   *          style名称
   * @param value
   *          style值
   */
  public void setRowStyleAttribute(int row, String attr, String value) {
    for (int col = 0; col < getColumnCount(); col++)
      setCellStyleAttribute(row, col, attr, value);
  }

  /**
   * 设置单元格样式
   * 
   * @param row
   *          行序号，包含表格的表头和表尾
   * @param col
   *          可见列序号
   * @param attr
   *          style名称
   * @param value
   *          style值
   */
  public void setCellStyleAttribute(int row, int col, String attr, String value) {
    DOM.setStyleAttribute(getCellFormatter().getElement(row, col), attr, value);
  }

  /**
   * 重新构造表格，如果只是需要刷新数据显示，请使用refresh()方法，那样速度会更快。
   * 
   */
  public void rebuild() {
    if (providerCache == null)
      throw new NullPointerException("尚未设置数据提供者，请用setProvider方法设置");

    // 行选择
    selections.clear();
    buildRowSelectorColumn();

    // 行数和列数
    resize(providerCache.getRowCount() + headerRowCount + footerRowCount, getVisibleColumnCount());

    // 表头
    buildHeader();

    // 表格主体
    for (int row = headerRowCount; row < getRowCount() - footerRowCount; row++) {
      buildRow(row);
    }

    // 表尾
    buildFooter();

    // 触发afterRefresh事件
    if (drawListeners != null)
      drawListeners.fireAfterRefresh(this);

    build = true;
  }

  /**
   * 构造表头
   * 
   */
  protected void buildHeader() {
    if (showHeader) {
      // showHeader==true时，构造表头
      for (int i = 0; i < columnDefs.size(); i++) {
        RGridColumnDef colDef = getColumnDef(i);
        if (!colDef.isVisible())
          continue;
        int col = colDef.getVisibleIndex();

        HorizontalPanel headerPanel = new HorizontalPanel();
        headerPanel.setStyleName("rb-Grid-headerpanel");
        headerPanel.setWidth("100%");

        // 列标题
        if (colDef.getHeaderWidget() == null) {
          HTML label = new HTML(colDef.getCaption() == null ? "" : colDef.getCaption() + "&nbsp;");
          label.setStyleName(STYLENAME_CAPTION);
          headerPanel.add(label);
        } else {
          colDef.getHeaderWidget().addStyleName(STYLENAME_HEADERWIDGET);
          headerPanel.add(colDef.getHeaderWidget());
        }

        // 排序图标
        HTML sortIcon = new HTML("&nbsp;");
        sortIcon.setStyleName(STYLENAME_SORTICON);
        headerPanel.add(sortIcon);
        headerPanel.setCellWidth(sortIcon, "100%");
        headerPanel.setCellHorizontalAlignment(sortIcon, HasAlignment.ALIGN_LEFT);
        colDef.setSortIcon(sortIcon);
        sortIcon.setVisible(colDef.isSortable());

        setWidget(0, col, headerPanel);

        getColumnFormatter().setWidth(col, colDef.getWidth());
        getCellFormatter().setStyleName(0, col, STYLENAME_HEADER);
      }
    } else {
      // showHeader==false时，清除之前构造表头时留下的样式
      if (getRowCount() > 0) {
        for (RGridColumnDef colDef : columnDefs) {
          if (!colDef.isVisible())
            continue;
          int col = colDef.getVisibleIndex();
          getCellFormatter().removeStyleName(0, col, STYLENAME_HEADER);
        }
      }
    }
  }

  /**
   * 构造一行
   * 
   * @param row
   */
  protected void buildRow(int row) {
    getRowFormatter().setStyleName(row, STYLENAME_ROW);

    // 条纹背景
    if (row % 2 == 0) {
      if (stripRows)
        getRowFormatter().addStyleName(row, STYLENAME_ROW_STRIP);
      else
        getRowFormatter().removeStyleName(row, STYLENAME_ROW_STRIP);
    }

    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (!colDef.isVisible())
        continue;

      int col = colDef.getVisibleIndex();
      if (colDef.getRendererFactory() != null) {
        RCellRenderer renderer = colDef.getRendererFactory().makeRenderer(this, colDef, row, col);
        setWidget(row, col, (Widget) renderer);
      } else {
        Object data = providerCache.getData(row - headerRowCount, colDef.getIndex());
        setText(row, col, data != null ? data.toString() : "");
      }

      // 对齐方式不等于默认值时才设置，以提高性能
      if (!colDef.getHorizontalAlign().equals(HasAlignment.ALIGN_LEFT))
        getCellFormatter().setHorizontalAlignment(row, col, colDef.getHorizontalAlign());
      if (!colDef.getVerticalAlign().equals(HasAlignment.ALIGN_MIDDLE))
        getCellFormatter().setVerticalAlignment(row, col, colDef.getVerticalAlign());

      // 折行
      if (!colDef.isWordWrap())
        getCellFormatter().setWordWrap(row, col, colDef.isWordWrap());

      // 触发事件
      if (drawListeners != null) {
        drawListeners.fireBuildCell(this, colDef, row, col);
        drawListeners.fireRefreshCell(this, colDef, row, col, providerCache.getData(row
            - headerRowCount, colDef.getIndex()));
      }
    }
  }

  /**
   * 构造表尾
   * 
   */
  protected void buildFooter() {
    if (!hasSummary)
      return;

    int summaryRow = getRowCount() - 1;
    getRowFormatter().setStyleName(summaryRow, STYLENAME_FOOTER);

    refreshSummary();

    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (colDef.getSummaryMethod() == RGridColumnDef.SUMMARY_METHOD_NONE)
        continue;

      // 对齐方式
      getCellFormatter().setHorizontalAlignment(summaryRow, colDef.getVisibleIndex(),
          colDef.getHorizontalAlign());
    }
  }

  /**
   * 默认的合计数据提供者
   * 
   * @return
   */
  protected RGridSummaryProvider getDefaultSummaryProvider() {
    if (defaultSummaryProvider == null)
      defaultSummaryProvider = new DefaultSummaryProvider();
    return defaultSummaryProvider;
  }

  /**
   * 重新计算所有列的可见列序号
   * 
   */
  protected void recalculateColumnVisibleIndex() {
    int col = 0;
    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (colDef.isVisible()) {
        colDef.setVisibleIndex(col);
        col++;
      } else {
        colDef.setVisibleIndex(-1);
      }
    }
  }

  /**
   * 构造行选择列
   * 
   */
  protected void buildRowSelectorColumn() {
    if (showRowSelector) {
      if (rowSelectorCol == null) {
        rowSelectorCol = new RGridColumnDef() {
          // sortable永远为false
          public void setSortable(boolean sortable) {
            super.setSortable(false);
          }
        };
        rowSelectorCol.setWidth("15px");
        rowSelectorCol.setRendererFactory(new RCheckBoxRendererFactory());
        RSimpleCheckBox selectorHeader = new RSimpleCheckBox();
        selectorHeader.addClickHandler(new SelectorHeaderHandler());
        rowSelectorCol.setHeaderWidget(selectorHeader);
      }
      ((RSimpleCheckBox) rowSelectorCol.getHeaderWidget()).setChecked(false);
      rowSelectorCol.getHeaderWidget().setVisible(!singleSelection);

      if (!columnDefs.contains(rowSelectorCol)) {
        addColumnDef(0, rowSelectorCol);
        if (rowSelectorListener == null)
          rowSelectorListener = new RowSelectorListener();
        addRGridClickListener(rowSelectorListener);
      }
    } else {
      if (rowSelectorCol != null) {
        columnDefs.remove(rowSelectorCol);
        recalculateColumnVisibleIndex();
      }
      removeRGridClickListener(rowSelectorListener);
    }
  }

  /**
   * 刷新表格数据显示，若表格还没有构造则会自动调用rebuild()
   * 
   */
  public void refresh() {
    if (!build) {
      rebuild();
      return;
    }

    // 刷新行数
    int oldRowCount = getRowCount();
    int rowCount = providerCache.getRowCount() + headerRowCount + footerRowCount;
    resizeRows(rowCount);

    // 如有必要，构造增加的行
    if (rowCount > oldRowCount) {
      for (int row = oldRowCount - footerRowCount; row < rowCount - footerRowCount; row++) {
        buildRow(row);
      }
    }

    // 刷新数据显示
    for (int row = headerRowCount; row < getRowCount() - footerRowCount; row++) {
      refreshRow(row);
    }

    // 刷新表尾
    refreshSummary();

    // 触发afterRefresh事件
    if (drawListeners != null)
      drawListeners.fireAfterRefresh(this);
  }

  /**
   * 刷新一行的数据显示
   * 
   * @param row
   */
  public void refreshRow(int row) {
    // 当前行可能被合计行使用过，所以需要重新设置style
    getRowFormatter().setStyleName(row, STYLENAME_ROW);

    // 条纹背景
    if (row % 2 == 0) {
      if (stripRows)
        getRowFormatter().addStyleName(row, STYLENAME_ROW_STRIP);
      else
        getRowFormatter().removeStyleName(row, STYLENAME_ROW_STRIP);
    }

    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (!colDef.isVisible())
        continue;

      refreshCell(row, colDef.getVisibleIndex());
    }
  }

  /**
   * 刷新一个单元格的数据显示
   * 
   * @param row
   * @param col
   *          可见列序号
   */
  public void refreshCell(int row, int col) {
    Widget widget = getWidget(row, col);
    RGridColumnDef colDef = getColumnDefByVisibleIndex(col);
    Object data = providerCache.getData(row - headerRowCount, colDef.getIndex());

    if (widget == null) {
      setText(row, col, data != null ? data.toString() : "");
    } else if (widget instanceof RCellRenderer) {
      ((RCellRenderer) widget).setValue(data);
    }

    // 触发事件
    if (drawListeners != null)
      drawListeners.fireRefreshCell(this, colDef, row, col, data);
  }

  /**
   * 刷新合计栏，如果所有列都是自动计算的（换言之，没有setCustomSummaryProvider），
   * 则无须显式的调用本方法，
   * 合计数值会在需要时自动刷新。只有在使用了customSummaryProvider即自定义的合计时才需要 调用本方法。
   * 
   */
  public void refreshSummary() {
    if (!hasSummary)
      return;

    int summaryRow = getRowCount() - 1;
    getRowFormatter().setStyleName(summaryRow, STYLENAME_FOOTER);

    for (int i = 0; i < columnDefs.size(); i++) {
      RGridColumnDef colDef = getColumnDef(i);
      if (!colDef.isVisible())
        continue;

      refreshSummary(colDef.getVisibleIndex());
    }
  }

  /**
   * 刷新合计栏的制定列，如果此列都是自动计算的（换言之，没有使用customSummaryProvider），
   * 则无须显式的调用本方法，
   * 合计数值会在需要时自动刷新。只有在使用了customSummaryProvider即自定义的合计时才需要 调用本方法。
   * 
   * @param col
   */
  public void refreshSummary(int col) {
    int summaryRow = getRowCount() - 1;
    RGridColumnDef colDef = getColumnDefByVisibleIndex(col);

    if (colDef.getSummaryMethod() == RGridColumnDef.SUMMARY_METHOD_NONE) {
      setText(summaryRow, col, "");
      return;
    }

    // 确定合计数据提供者
    RGridSummaryProvider summaryProvider;
    if (colDef.getSummaryMethod() == RGridColumnDef.SUMMARY_METHOD_CUSTOM) {
      if (customSummaryProvider == null)
        throw new NullPointerException("存在自定义合计列，但并未设置自定义的合集数据提供者，请用setCustomSummaryProvider方法设置");
      summaryProvider = customSummaryProvider;
    } else {
      summaryProvider = getDefaultSummaryProvider();
    }

    // 从provider得到合计值
    String summaryValue = summaryProvider.getSummary(colDef.getIndex());

    // 空值用空串代替
    summaryValue = summaryValue == null ? "" : summaryValue;

    // 前面加上说明文字，求和时不必加，因为其显而易见
    String prefix = colDef.getSummaryMethod() == RGridColumnDef.SUMMARY_METHOD_SUM ? "" : colDef
        .getSummaryMethodDesc();
    prefix = prefix.equals("") ? "" : prefix + ": ";

    setText(summaryRow, col, prefix + summaryValue);
  }

  public void onBrowserEvent(Event event) {
    super.onBrowserEvent(event);

    switch (DOM.eventGetType(event)) {

    case Event.ONMOUSEOVER:
    case Event.ONMOUSEOUT:
      Element td = getEventTargetCell(event);
      if (td == null)
        break;
      Element tr = DOM.getParent(td);

      // 表头
      for (int i = 0; i < headerRowCount; i++) {
        if (DOM.getChild(getBodyElement(), i).equals(tr)) {
          int index = DOM.getChildIndex(tr, td);
          for (int j = 0; j < columnDefs.size(); j++) {
            RGridColumnDef colDef = (RGridColumnDef) columnDefs.get(j);
            if (colDef.getVisibleIndex() == index) {
              if (colDef.isSortable()) {
                UIObject.setStyleName(td, STYLENAME_HEADER_HOVER,
                    DOM.eventGetType(event) == Event.ONMOUSEOVER);
              }
              return;
            }
          }
          return;
        }
      }

      // 忽略表尾
      for (int i = getRowCount() - 1; i >= getRowCount() - footerRowCount; i--)
        if (DOM.getChild(getBodyElement(), i).equals(tr))
          return;

      // hoverRow
      if (hoverRow)
        UIObject
            .setStyleName(tr, STYLENAME_ROW_HOVER, DOM.eventGetType(event) == Event.ONMOUSEOVER);

      break;
    }
  }

  /**
   * 数据提供者的缓存。在计算合计值时可用使用缓存，从而减少对provider的调用，以提高性能。
   * 
   * @author LiQi
   * 
   */
  private class DataProviderCache implements RGridDataProvider {

    private RGridDataProvider provider;
    private int rowCount = -1;
    private List data;

    public DataProviderCache() {
      data = new ArrayList();
    }

    public RGridDataProvider getProvider() {
      return provider;
    }

    public void setProvider(RGridDataProvider provider) {
      this.provider = provider;
    }

    /**
     * 刷新数据
     */
    public Object getData(int row, int col) {
      if (provider == null)
        throw new NullPointerException("尚未设置数据提供者，请用setProvider方法设置");

      // 在缓存冲创建适当的位置
      if (row >= data.size()) {
        for (int i = data.size(); i <= row; i++)
          data.add(new ArrayList());
      }
      List dataLine = (List) data.get(row);
      if (col >= dataLine.size()) {
        for (int i = dataLine.size(); i <= col; i++)
          dataLine.add(null);
      }

      Object value = provider.getData(row, col);
      dataLine.set(col, value);
      return value;
    }

    /**
     * 刷新行号
     */
    public int getRowCount() {
      if (provider == null)
        throw new NullPointerException("尚未设置数据提供者，请用setProvider方法设置");

      rowCount = provider.getRowCount();
      return rowCount;
    }

    /**
     * 获得缓存中的数据
     * 
     * @param row
     * @param col
     * @return
     */
    public Object getCachedData(int row, int col) {
      if (row >= data.size())
        return null;
      List dataLine = (List) data.get(row);
      if (col >= dataLine.size())
        return null;
      return dataLine.get(col);
    }

    /**
     * 获得缓存的行数
     * 
     * @return
     */
    public int getCachedRowCount() {
      return rowCount;
    }

  }

  /**
   * 行选择事件处理
   * 
   * @author LiQi
   * 
   */
  private class RowSelectorListener implements RGridClickListener {
    public void onClick(RGrid grid, RGridColumnDef colDef, int row, int col, Widget sender) {
      if (!colDef.equals(rowSelectorCol))
        return;

      Integer selection = new Integer(row);
      if (!((RCheckBoxRenderer) sender).isChecked()) {
        selections.remove(selection);
        getRowFormatter().removeStyleName(row, STYLENAME_ROW_SELECTED);
      } else {
        selectRow(row);
      }
    }
  };

  /**
   * 全选和清除全选事件处理
   * 
   * @author LiQi
   * 
   */
  private class SelectorHeaderHandler implements ClickHandler {
    public void onClick(ClickEvent event) {
      if (((RSimpleCheckBox) event.getSource()).isChecked())
        selectAllRows();
      else
        deselectAllRows();
    }
  }

  /**
   * 把表格的ClickHandler适配到RGridClickListener。
   * <p>
   * 只对不包含控件的单元格和表头执行这种适配，
   * 包含控件的单元格已经由RendererFactory建立了触发RGridClickListener的机制。
   * 
   * @author LiQi
   * 
   */
  //  private class GridClickListenerAdapter implements TableListener {
  //    public void onCellClicked(SourcesTableEvents sender, int row, int cell) {
  //      RGridColumnDef colDef = getColumnDefByVisibleIndex(cell);
  //
  //      // 点击表头排序
  //      if (row < headerRowCount && colDef.isSortable()) {
  //        if (colDef.getSort() == null)
  //          colDef.setSort(colDef.getDefaultSort());
  //        else if (colDef.getSort().equals(SORT_ASC))
  //          colDef.setSort(SORT_DESC);
  //        else
  //          colDef.setSort(SORT_ASC);
  //
  //        refreshSortIcon(colDef);
  //
  //        if (!colDef.equals(sortColDef)) {
  //          getCellFormatter().addStyleName(row, cell, STYLENAME_HEADER_SORT);
  //
  //          if (sortColDef != null) {
  //            sortColDef.setSort(null);
  //            getCellFormatter().removeStyleName(row, sortColDef.getVisibleIndex(),
  //                STYLENAME_HEADER_SORT);
  //            refreshSortIcon(sortColDef);
  //          }
  //
  //          sortColDef = colDef;
  //        }
  //
  //        if (sortListeners != null)
  //          sortListeners.fireSort(RGrid.this, colDef, colDef.getSort());
  //      }
  //
  //      if (colDef.getRendererFactory() == null)
  //        fireRGridClick(colDef, row, cell, null);
  //    }
  //
  //    private void refreshSortIcon(RGridColumnDef colDef) {
  //      colDef.getSortIcon().removeStyleDependentName(DEPENDENT_STYLENAME_ASC);
  //      colDef.getSortIcon().removeStyleDependentName(DEPENDENT_STYLENAME_DESC);
  //
  //      if (SORT_ASC.equals(colDef.getSort()))
  //        colDef.getSortIcon().addStyleDependentName(DEPENDENT_STYLENAME_ASC);
  //      else if (SORT_DESC.equals(colDef.getSort()))
  //        colDef.getSortIcon().addStyleDependentName(DEPENDENT_STYLENAME_DESC);
  //    }
  //  }
  //
  private class GridClickHandlerAdapter implements ClickHandler {

    public void onClick(ClickEvent event) {
      Cell cell = getCellForEvent(event);
      if (cell == null)
        return;
      int row = cell.getRowIndex();
      int col = cell.getCellIndex();

      RGridColumnDef colDef = getColumnDefByVisibleIndex(col);

      // 点击表头排序
      if (row < headerRowCount && colDef.isSortable()) {
        if (colDef.getSort() == null)
          colDef.setSort(colDef.getDefaultSort());
        else if (colDef.getSort().equals(SORT_ASC))
          colDef.setSort(SORT_DESC);
        else
          colDef.setSort(SORT_ASC);

        refreshSortIcon(colDef);

        if (!colDef.equals(sortColDef)) {
          getCellFormatter().addStyleName(row, col, STYLENAME_HEADER_SORT);

          if (sortColDef != null) {
            sortColDef.setSort(null);
            getCellFormatter().removeStyleName(row, sortColDef.getVisibleIndex(),
                STYLENAME_HEADER_SORT);
            refreshSortIcon(sortColDef);
          }

          sortColDef = colDef;
        }

        if (sortListeners != null)
          sortListeners.fireSort(RGrid.this, colDef, colDef.getSort());
      }

      if (colDef.getRendererFactory() == null)
        fireRGridClick(colDef, row, col, null);
    }

    private void refreshSortIcon(RGridColumnDef colDef) {
      colDef.getSortIcon().removeStyleDependentName(DEPENDENT_STYLENAME_ASC);
      colDef.getSortIcon().removeStyleDependentName(DEPENDENT_STYLENAME_DESC);

      if (SORT_ASC.equals(colDef.getSort()))
        colDef.getSortIcon().addStyleDependentName(DEPENDENT_STYLENAME_ASC);
      else if (SORT_DESC.equals(colDef.getSort()))
        colDef.getSortIcon().addStyleDependentName(DEPENDENT_STYLENAME_DESC);
    }
  }

  /**
   * 默认的合计数据提供者
   * 
   * @author LiQi
   * 
   */
  private class DefaultSummaryProvider implements RGridSummaryProvider {

    /** 默认的数值格式 */
    private NumberFormat defaultNumberFormat;

    public DefaultSummaryProvider() {
      defaultNumberFormat = NumberFormat.getFormat("0.###");
    }

    public String getSummary(int col) {
      for (int i = 0; i < columnDefs.size(); i++) {
        RGridColumnDef colDef = (RGridColumnDef) columnDefs.get(i);
        if (colDef.getIndex() != col)
          continue;

        switch (colDef.getSummaryMethod()) {
        case RGridColumnDef.SUMMARY_METHOD_COUNT:
          return getCount(colDef);
        case RGridColumnDef.SUMMARY_METHOD_SUM:
          return getSum(colDef);
        case RGridColumnDef.SUMMARY_METHOD_AVERAGE:
          return getAverage(colDef);
        case RGridColumnDef.SUMMARY_METHOD_MAX:
          return getMax(colDef);
        case RGridColumnDef.SUMMARY_METHOD_MIN:
          return getMin(colDef);
        }

      }
      return "";
    }

    /** 计数，为空的单元格不计入 */
    private String getCount(RGridColumnDef colDef) {
      int count = 0;
      for (int i = 0; i < providerCache.getCachedRowCount(); i++) {
        if (providerCache.getCachedData(i, colDef.getIndex()) != null)
          count++;
      }
      return new Integer(count).toString();
    }

    /** 求和 */
    private String getSum(RGridColumnDef colDef) {
      double sum = 0;
      for (int i = 0; i < providerCache.getCachedRowCount(); i++) {
        Object value = providerCache.getCachedData(i, colDef.getIndex());
        if (value == null)
          continue;
        if (value instanceof Number)
          sum += ((Number) value).doubleValue();
        else if (value instanceof JsBigDecimal)
          sum += ((JsBigDecimal) value).doubleValue();
      }
      return getNumberFormat(colDef).format(sum);
    }

    /** 平均 */
    private String getAverage(RGridColumnDef colDef) {
      double sum = 0;
      int count = 0;
      for (int i = 0; i < providerCache.getCachedRowCount(); i++) {
        Object value = providerCache.getCachedData(i, colDef.getIndex());
        if (value == null)
          continue;
        count++;
        if (value instanceof Number)
          sum += ((Number) value).doubleValue();
        else if (value instanceof JsBigDecimal)
          sum += ((JsBigDecimal) value).doubleValue();
      }
      return getNumberFormat(colDef).format(sum / count);
    }

    /** 最大值 */
    private String getMax(RGridColumnDef colDef) {
      int maxIndex = -1;
      double maxValue = 0;
      for (int i = 0; i < providerCache.getCachedRowCount(); i++) {
        Object value = providerCache.getCachedData(i, colDef.getIndex());
        if (value == null)
          continue;
        double doubleValue = 0;
        if (value instanceof Number)
          doubleValue = ((Number) value).doubleValue();
        else if (value instanceof JsBigDecimal)
          doubleValue = ((JsBigDecimal) value).doubleValue();

        if (maxIndex == -1 || doubleValue > maxValue) {
          maxIndex = i;
          maxValue = doubleValue;
        }
      }
      return maxIndex == -1 ? "" : getNumberFormat(colDef).format(maxValue);
    }

    /** 最小值 */
    private String getMin(RGridColumnDef colDef) {
      int minIndex = -1;
      double minValue = 0;
      for (int i = 0; i < providerCache.getCachedRowCount(); i++) {
        Object value = providerCache.getCachedData(i, colDef.getIndex());
        if (value == null)
          continue;
        double doubleValue = 0;
        if (value instanceof Number)
          doubleValue = ((Number) value).doubleValue();
        else if (value instanceof JsBigDecimal)
          doubleValue = ((JsBigDecimal) value).doubleValue();

        if (minIndex == -1 || doubleValue < minValue) {
          minIndex = i;
          minValue = doubleValue;
        }
      }
      return minIndex == -1 ? "" : getNumberFormat(colDef).format(minValue);
    }

    /**
     * 从列定义的RendererFactory取格式，如果取不到，则用默认格式
     * 
     * @param colDef
     * @return
     */
    private NumberFormat getNumberFormat(RGridColumnDef colDef) {
      if (colDef.getRendererFactory() != null
          && colDef.getRendererFactory() instanceof HasNumberFormat)
        return ((HasNumberFormat) colDef.getRendererFactory()).getFormat();
      else
        return defaultNumberFormat;
    }
  }

  //************************************************************************************************
  // 性能测试工具

  //  private Map perfData;
  //
  //  private void putPerfData(String key, Date startTime) {
  //    long value = new Date().getTime() - startTime.getTime();
  //    if (perfData == null)
  //      perfData = new HashMap();
  //    long oldValue = perfData.containsKey(key) ? ((Long) perfData.get(key)).longValue() : 0;
  //    perfData.put(key, new Long(oldValue + value));
  //  }
  //
  //  private String getPerfData() {
  //    String s = "";
  //    for (Iterator i = perfData.keySet().iterator(); i.hasNext();) {
  //      String key = (String) i.next();
  //      s += key + " " + ((Long) perfData.get(key)).toString() + "\n";
  //    }
  //    return s;
  //  }

  //************************************************************************************************

}
